#include "driver_gpio.h"

/* ================================
 * PORT A
 * ================================ */
void gpio_porta_write(uint8_t value)
{
    REG_PL_WR(GPIO_PORTA_DATA, value);
}

uint8_t gpio_porta_read(void)
{
    return REG_PL_RD(GPIO_PORTA_DATA);
}

void gpio_porta_set_dir(uint8_t dir)
{
    REG_PL_WR(GPIO_PORTA_DIR, dir);
}

uint8_t gpio_porta_get_dir(void)
{
    return REG_PL_RD(GPIO_PORTA_DIR);
}

/* ================================
 * PORT B
 * ================================ */
void gpio_portb_write(uint8_t value)
{
    REG_PL_WR(GPIO_PORTB_DATA, value);
}

uint8_t gpio_portb_read(void)
{
    return REG_PL_RD(GPIO_PORTB_DATA);
}

void gpio_portb_set_dir(uint8_t dir)
{
    REG_PL_WR(GPIO_PORTB_DIR, dir);
}

uint8_t gpio_portb_get_dir(void)
{
    return REG_PL_RD(GPIO_PORTB_DIR);
}

/* ================================
 * PORT C
 * ================================ */
void gpio_portc_write(uint8_t value)
{
    REG_PL_WR(GPIO_PORTC_DATA, value);
}

uint8_t gpio_portc_read(void)
{
    return REG_PL_RD(GPIO_PORTC_DATA);
}

void gpio_portc_set_dir(uint8_t dir)
{
    REG_PL_WR(GPIO_PORTC_DIR, dir);
}

uint8_t gpio_portc_get_dir(void)
{
    return REG_PL_RD(GPIO_PORTC_DIR);
}

/* ================================
 * PORT D
 * ================================ */
void gpio_portd_write(uint8_t value)
{
    REG_PL_WR(GPIO_PORTD_DATA, value);
}

uint8_t gpio_portd_read(void)
{
    return REG_PL_RD(GPIO_PORTD_DATA);
}

void gpio_portd_set_dir(uint8_t dir)
{
    REG_PL_WR(GPIO_PORTD_DIR, dir);
}

uint8_t gpio_portd_get_dir(void)
{
    return REG_PL_RD(GPIO_PORTD_DIR);
}

/* ================================
 * 单个 GPIO Pin 操作
 * ================================ */
void gpio_set_dir(enum system_port_t port, enum system_port_bit_t bit, uint8_t dir)
{
    uint8_t tmp;
    switch(port)
    {
        case GPIO_PORT_A:
            tmp = gpio_porta_get_dir();
            if(dir)
                tmp |= (1 << bit);
            else
                tmp &= ~(1 << bit);
            gpio_porta_set_dir(tmp);
            break;

        case GPIO_PORT_B:
            tmp = gpio_portb_get_dir();
            if(dir)
                tmp |= (1 << bit);
            else
                tmp &= ~(1 << bit);
            gpio_portb_set_dir(tmp);
            break;

        case GPIO_PORT_C:
            tmp = gpio_portc_get_dir();
            if(dir)
                tmp |= (1 << bit);
            else
                tmp &= ~(1 << bit);
            gpio_portc_set_dir(tmp);
            break;

        case GPIO_PORT_D:
            tmp = gpio_portd_get_dir();
            if(dir)
                tmp |= (1 << bit);
            else
                tmp &= ~(1 << bit);
            gpio_portd_set_dir(tmp);
            break;

        default:
            break;
    }
}

uint8_t gpio_get_pin_value(enum system_port_t port, enum system_port_bit_t bit)
{
    uint8_t val = 0;
    switch(port)
    {
        case GPIO_PORT_A:
            val = gpio_porta_read();
            break;
        case GPIO_PORT_B:
            val = gpio_portb_read();
            break;
        case GPIO_PORT_C:
            val = gpio_portc_read();
            break;
        case GPIO_PORT_D:
            val = gpio_portd_read();
            break;
        default:
            break;
    }
    return (val >> bit) & 0x1;
}

void gpio_set_pin_value(enum system_port_t port, enum system_port_bit_t bit, uint8_t value)
{
    uint8_t tmp = 0;
    switch(port)
    {
        case GPIO_PORT_A:
            tmp = gpio_porta_read();
            if(value)
                tmp |= (1 << bit);
            else
                tmp &= ~(1 << bit);
            gpio_porta_write(tmp);
            break;

        case GPIO_PORT_B:
            tmp = gpio_portb_read();
            if(value)
                tmp |= (1 << bit);
            else
                tmp &= ~(1 << bit);
            gpio_portb_write(tmp);
            break;

        case GPIO_PORT_C:
            tmp = gpio_portc_read();
            if(value)
                tmp |= (1 << bit);
            else
                tmp &= ~(1 << bit);
            gpio_portc_write(tmp);
            break;

        case GPIO_PORT_D:
            tmp = gpio_portd_read();
            if(value)
                tmp |= (1 << bit);
            else
                tmp &= ~(1 << bit);
            gpio_portd_write(tmp);
            break;

        default:
            break;
    }
}
